package pl.droidsonroids.gif;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.Text;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.PixelMapElement;
import ohos.agp.render.Canvas;
import ohos.app.Context;
import ohos.global.resource.NotExistException;
import ohos.global.resource.ResourceManager;
import ohos.global.resource.WrongTypeException;

import java.io.IOException;

/**
 * A {@link Text} which handles GIFs as compound drawables. NOTE:
 * {@code ohos:element_start} and {@code ohos:element_end} from XML are
 * not supported but can be set using
 * {@link #setAroundElementsPadding(int)}
 *
 * @author koral--
 */
public class GifTextView extends Text implements Component.BindStateChangedListener, Component.DrawTask {
    private Element left;
    private Element right;
    private Element top;
    private Element bottom;
    private Element backGround;

    private GifViewUtils.GifViewAttributes viewAttributes;

    /**
     * A corresponding superclass constructor wrapper.
     * @param context context
     */
    public GifTextView(Context context) {
        super(context);
        addDrawTask(this);
    }

    public GifTextView(Context context, AttrSet attrs) throws NotExistException, WrongTypeException, IOException {
        super(context, attrs);
        addDrawTask(this);
    }

    public GifTextView(Context context, AttrSet attrs, String styleName)
            throws NotExistException, WrongTypeException, IOException {
        super(context, attrs, styleName);
        addDrawTask(this);
    }

    private static void setDrawablesVisible(final Element[] drawables, final boolean visible) {
        for (final Element drawable : drawables) {
            if (drawable != null) {
                drawable.setVisible(visible, false);
            }
        }
    }

    private void init(AttrSet attrs, String defStyle, int defStyleRes)
            throws IOException, NotExistException, WrongTypeException {
        if (attrs != null) {
            Element leftElement = getGifOrDefaultDrawable(attrs.getAttr("drawableLeft").get().getIntegerValue());
            Element topElement = getGifOrDefaultDrawable(attrs.getAttr("drawableTop").get().getIntegerValue());
            Element rightElement = getGifOrDefaultDrawable(attrs.getAttr("drawableRight").get().getIntegerValue());
            Element bottomElement = getGifOrDefaultDrawable(attrs.getAttr("drawableBottom").get().getIntegerValue());
            Element start = getGifOrDefaultDrawable(attrs.getAttr("drawableStart").get().getIntegerValue());
            Element end = getGifOrDefaultDrawable(attrs.getAttr("drawableEnd").get().getIntegerValue());
            if (getLayoutDirection() == LayoutDirection.LTR) {
                if (start == null) {
                    start = leftElement;
                }
                if (end == null) {
                    end = rightElement;
                }
            } else {
                if (start == null) {
                    start = rightElement;
                }
                if (end == null) {
                    end = leftElement;
                }
            }
            setAroundElements(start, topElement, end, bottomElement);
            setBackground(getGifOrDefaultDrawable(attrs.getAttr("background").get().getIntegerValue()));
            viewAttributes = new GifViewUtils.GifViewAttributes(this, attrs, 0, 0);
            applyGifViewAttributes();
        }
        viewAttributes = new GifViewUtils.GifViewAttributes();
    }

    private void applyGifViewAttributes() {
        if (viewAttributes.mLoopCount < 0) {
            return;
        }
        for (final Element element : getAroundElements()) {
            GifViewUtils.applyLoopCount(viewAttributes.mLoopCount, element);
        }
        for (final Element element : getAroundElementsRelative()) {
            GifViewUtils.applyLoopCount(viewAttributes.mLoopCount, element);
        }
        GifViewUtils.applyLoopCount(viewAttributes.mLoopCount, getBackgroundElement());
    }

    @SuppressWarnings("deprecation") // Resources#getDrawable(int)
    private Element getGifOrDefaultDrawable(int resId) throws IOException, NotExistException, WrongTypeException {
        if (resId == 0) {
            return null;
        }
        final ResourceManager resources = getResourceManager();
        final String resourceTypeName = resources.getIdentifier(resId);
        try {
            return new GifDrawable(getContext(), resources, resId);
        } catch (IOException | NotExistException ignored) {
            // ignored
        }
        return GifViewUtils.getElement(getContext(), resId);
    }

    /**
     * Sets Elements
     * @param left left element
     * @param top top element
     * @param right right element
     * @param bottom bottom element
     */
    public void setElements(Element left, Element top, Element right, Element bottom) {
        this.left = left;
        this.right = right;
        this.top = top;
        this.bottom = bottom;
        if (left instanceof GifDrawable) {
            ((GifDrawable) this.left).setElementCallback(this);
        }
    }

    /**
     * Sets loopcount
     * @param count count
     */
    public void setLoopCount(int count) {
        if (left instanceof GifDrawable) {
            ((GifDrawable) this.left).setLoopCount(count);
        }
        if (right instanceof GifDrawable) {
            ((GifDrawable) this.right).setLoopCount(count);
        }
        if (top instanceof GifDrawable) {
            ((GifDrawable) this.top).setLoopCount(count);
        }
        if (bottom instanceof GifDrawable) {
            ((GifDrawable) this.bottom).setLoopCount(count);
        }
    }

    /**
     * Sets background
     * @param resId resource id
     * @throws NotExistException exception
     * @throws WrongTypeException exception
     * @throws IOException exception
     */
    public void setBackgroundResource(int resId) throws NotExistException, WrongTypeException, IOException {
        setBackground(getGifOrDefaultDrawable(resId));
    }

    private void setCompoundDrawablesVisible(final boolean visible) {
        setDrawablesVisible(getAroundElements(), visible);
        setDrawablesVisible(getAroundElementsRelative(), visible);
    }

    /**
     * Sets Animation
     * @param freezesAnimation freezesAnimation
     */
    public void setFreezesAnimation(boolean freezesAnimation) {
        viewAttributes.freezesAnimation = freezesAnimation;
    }

    @Override
    public void onComponentBoundToWindow(Component component) {
        setCompoundDrawablesVisible(true);
    }

    @Override
    public void onComponentUnboundFromWindow(Component component) {
        setCompoundDrawablesVisible(false);
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        Element ele1 = null;
        Element ele2 = null;
        Element ele3 = null;
        Element ele4 = null;
        if (backGround != null && backGround instanceof GifDrawable) {
            Element ele = new PixelMapElement(((GifDrawable)backGround).mPixelMap);
            setBackground(ele);
        }
        if (left == null || right == null || top == null || bottom == null) {
            return;
        }
        if (left instanceof GifDrawable) {
            ele1 = new PixelMapElement(((GifDrawable) left).mPixelMap);
        }
        if (top instanceof GifDrawable) {
            ele2 = new PixelMapElement(((GifDrawable) top).mPixelMap);
        }
        if (right instanceof GifDrawable) {
            ele3 = new PixelMapElement(((GifDrawable) right).mPixelMap);
        }
        if (bottom instanceof GifDrawable) {
            ele4 = new PixelMapElement(((GifDrawable) bottom).mPixelMap);
        }
        setAroundElementsRelative(ele1, ele2, ele3, ele4);
    }

    /**
     * Set Background
     * @param element element
     */
    public void setBackgroundElement(Element element) {
        backGround = element;
        if (backGround instanceof GifDrawable) {
            ((GifDrawable) backGround).setElementCallback(this);
        }
    }

    @Override
    public Element getLeftElement() {
        return left;
    }

    @Override
    public Element getRightElement() {
        return right;
    }

    @Override
    public Element getTopElement() {
        return top;
    }

    @Override
    public Element getBottonElement() {
        return bottom;
    }

    @Override
    public Element getBackgroundElement() {
        return backGround;
    }
}
